/*
 * @Author: SJChen
 * @Date: 2021-09-16 22:09:09
 * @LastEditTime: 2022-01-10 00:32:29
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: /iEDA/src/iTDP/cellMoveEngine/subGradient/DrivenStrengthCellMovement.h
 */

#pragma once

#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <unordered_map>
#include <vector>

#include "QuadraticTDP.h"
#include "Point.hh"
#include "contest_db.h"

namespace ieda_contest {

class DrivenStrengthCellMovement
{
 public:
  DrivenStrengthCellMovement() = delete;
  DrivenStrengthCellMovement(ContestDB* database);
  DrivenStrengthCellMovement(const DrivenStrengthCellMovement&) = delete;
  DrivenStrengthCellMovement(DrivenStrengthCellMovement&&) = delete;
  ~DrivenStrengthCellMovement() = default;

  DrivenStrengthCellMovement& operator=(const DrivenStrengthCellMovement&) = delete;
  DrivenStrengthCellMovement& operator=(DrivenStrengthCellMovement&&) = delete;

  void runDrivenStrengthAwareOpt(QuadraticTDP* _quadratic_tdp);

 private:
  ContestDB* _Contest_database;
  QuadraticTDP* _quadratic_tdp;

  std::map<ContestInstance*, bool> moved;
  std::string _optType{"driver"};
  bool _optionDontMoveRegistersAndLCBs{true};
  bool _clsEnableMaxDisplacementConstraint{false};
  double _original_tns;
  double _original_wns;
  int _iter{0};

  // opt flow
  void runClusteredMove();
  void runBufferBalancing();
  void runLoadOpt();

  // opt methods
  void runOneStepClusteredMovement(const int N);
  void clusterNeighborCriticalNets(ContestPin* criticalPin, const bool dontMoveRegisters);
  bool doBufferBalancing(ContestInstance* buffer);
  bool checkMaxDisplacementViolation(const bool hideMessageIfPass);

  // utility
  void runMoveNonCriticalSinksOfCriticalNetsToSteinerPoint(const bool DontMoveRegistersAndLCBs);
  void runMoveNonCriticalSinksOfCriticalNetsToDriver(const bool DontMoveRegistersAndLCBs);

};

}  // namespace ipl
